using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using Instruments;
using dotMath;

namespace ScopeTest {
	public partial class Form1 : Form {

		List<TextBox> textBoxes = new List<TextBox>();

		int samples = 10;
		int samplesGenerated = 0;

		double eqTime = 0.025;

		public Form1() {
			InitializeComponent();
		}

		private void startButton_Click(object sender, EventArgs e) {
			if ( startButton.Text == "Start" ) {

				foreach ( TextBox t in textBoxes )
					textBox_Leave(t, null);

				scopeControl.Start();

				samplesGenerated = 0;
				uTimer.Reset();
				uTimer.Start();

				updateTimer.Interval = (int)(eqTime * 1000);
				updateTimer.Start();

				startButton.Text = "Stop";


			} else {
				uTimer.Stop();
				updateTimer.Stop();
				scopeControl.Stop();
				startButton.Text = "Start";
			}
		}

		System.Diagnostics.Stopwatch uTimer = new System.Diagnostics.Stopwatch();

		private void updateTimer_Tick(object sender, EventArgs e) {

			// samples to generate
			int i,samplesToGen = (int) (( uTimer.ElapsedMilliseconds * samples ) / ( eqTime * 1000 ));

			// this is the hard way to commit data.. but its because
			// we're generating it on the fly. Generally, you would already
			// have the data aggregated somehow and so you could just use AddPoints()

			// add data to each trace
			for ( i = samplesGenerated; i < samplesToGen; i++ ) {

				// begin the collection process
				scopeControl.BeginAddPoint();

				double tm = i * ( eqTime / 10 );

				// add each point for each trace
				for ( int j = 0; j < textBoxes.Count; j++ ) {

					TextBox t = textBoxes[j];

					if ( t.Tag == null )
						continue;

					lock ( t.Tag ) {

						EqCompiler equation = t.Tag as EqCompiler;

						equation.SetVariable("t", tm);

						scopeControl.AddPoint(j, (float)equation.Calculate());

					}
				}
				
				// commit the trace data
				scopeControl.EndAddPoint();

			}

			samplesGenerated = i;

		}

		private void Form1_Load(object sender, EventArgs e) {

			Color [] colors = new Color[4];

			colors[0] = Color.Blue;
			colors[1] = Color.Red;
			colors[2] = Color.Yellow;
			colors[3] = Color.Green;

			textBoxes.Add(textBox1);
			textBoxes.Add(textBox2);
			textBoxes.Add(textBox3);
			textBoxes.Add(textBox4);

			foreach ( TextBox t in textBoxes )
				t.Tag = null;

			for ( int i = 0; i < 4; i++ ) {

				Trace d = new Trace();
				d.TraceColor = colors[i];

				scopeControl.Traces.Add(d);

			}

			trackBar1_Scroll(null, null);

		}

		private void textBox_Leave(object sender, EventArgs e) {

			EqCompiler equation;
			TextBox t = sender as TextBox;

			// validate the equation, and if its not valid, then
			// re-focus the textbox
			if ( t.Text.Trim().Equals("") ) {

				if ( t.Tag != null )
					lock ( t.Tag ) {
						t.Tag = null;
					}

				return;
			}

			try {

				equation = new EqCompiler(t.Text, true);
				equation.Compile();

				// set useful variables to something
				equation.SetVariable("e", Math.E);
				equation.SetVariable("pi", Math.PI);

				// just generically set these
				equation.SetVariable("t", 0);

				double testValue = equation.Calculate();

				// make sure theres no nonsense here
				foreach ( string var in equation.GetVariableList() )
					if ( var != "e" && var != "pi" && var != "t" )
						throw new ApplicationException(String.Format("Invalid variable \"{0}\" used in equation.", var));

				// i think this works
				if ( t.Tag == null )
					t.Tag = equation;
				else
					lock ( t.Tag ) {
						t.Tag = equation;
					}

			} catch ( Exception ex ) {
				MessageBox.Show(String.Format("Warning: Invalid equation! {0}", ex.Message), "Error");
			}
		}

		private void samples_TextChanged(object sender, EventArgs e) {
			try {
				samples = Convert.ToInt32(samplesTextbox.Text);
			} catch {
				samplesTextbox.Text = samples.ToString();
			}
		}

		private void button1_Click(object sender, EventArgs e) {
			if ( button1.Text == "Set Color=Blue" ) {
				scopeControl.Traces[0].TraceColor = Color.Blue;
				button1.Text = "Set Color=Gold";
			} else {
				scopeControl.Traces[0].TraceColor = Color.Gold;
				button1.Text = "Set Color=Blue";
			}
		}

		private void checkBox1_CheckedChanged(object sender, EventArgs e) {
			scopeControl.Traces[0].Visible = !scopeControl.Traces[0].Visible;
		}

		private void checkBox2_CheckedChanged(object sender, EventArgs e) {
			scopeControl.Traces[1].Visible = !scopeControl.Traces[1].Visible;
		}

		private void checkBox3_CheckedChanged(object sender, EventArgs e) {
			scopeControl.Traces[2].Visible = !scopeControl.Traces[2].Visible;
		}

		private void checkBox4_CheckedChanged(object sender, EventArgs e) {
			scopeControl.Traces[3].Visible = !scopeControl.Traces[3].Visible;
		}

		private void trackBar1_Scroll(object sender, EventArgs e) {

			// neat algorithm: use logarithms to establish a base value
			// (1us, 10us, 100us, 1ms .. ), then double it modulus amount 
			// of times to get the intermediate values (1x,2x,4x)

			scopeControl.MicroSecondsPerUnit =
				(int)Math.Pow(10, trackBar1.Value / 3) *
				(int)Math.Pow(2, trackBar1.Value % 3);

		}

		private void trackBar2_Scroll(object sender, EventArgs e) {
			scopeControl.Traces[0].ZeroPositionY = trackBar2.Value - 5;
		}

		private void trackBar3_Scroll(object sender, EventArgs e) {
			scopeControl.Traces[0].MilliPerUnit =
				(int)Math.Pow(10, trackBar3.Value / 3) *
				(int)Math.Pow(2, trackBar3.Value % 3);
		}

	}
}